﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Serialization;


//在OrderService中添加一个Export方法，
//可以将所有的订单序列化为XML文件；
//添加一个Import方法可以从XML文件中载入订单。

namespace OrderApplication
{
    public class Program
    {
        static void Main(string[] args)
        {
            OrderService orders = new OrderService();
            bool flag = true;
            while (flag)
            {
                Console.WriteLine("Input 1 to add order\n" +
                    "Input 2 to remove order\n" +
                    "Input 3 to search order\n" +
                    "Input 4 to show order\n" +
                    "Input 5 to serializer\n" +
                    "Input 6 to deserializer\n" +
                    "Input 7 to quit");
                string input = Console.ReadLine();
                switch (input)
                {
                    case "1":

                        Console.WriteLine("Input id, customer and date of the order to add:");
                        int id = Convert.ToInt32(Console.ReadLine());
                        string customer = Console.ReadLine();
                        string date = Console.ReadLine();
                        Order order = new Order(id, customer, date);
                        orders.addOrder(order);
                        break;
                    case "2":
                        Console.WriteLine("Input the id of the order to remove:");
                        int orderId = Convert.ToInt32(Console.ReadLine());
                        orders.removeOrder(orderId);
                        break;
                    case "3":
                        Console.WriteLine("Input 1 to search orders in money " +
                            "Input 2 to search orders in customer");
                        break;
                    case "4":
                        orders.showOrders();
                        break;
                    case "5":
                        orders.export();
                        break;
                    case "6":
                        orders.import();
                        break;
                    case "7":
                        flag = false;
                        break;
                    default:
                        Console.WriteLine("Input error! Please input the choose again!");
                        break;


                }
            }
        }
    }


    public interface IOrderService
    {
        void addOrder(Order order);
        void removeOrder(int i);
        List<Order> searchOrder(string op, object o);
        void showOrders();
    }
    public class OrderDetails
    {
        private string name;
        public string Name { get { return name; } set { name = value; } }
        private int number;
        public int Number { get { return number; } set { number = value; } }
        private double price;
        public double Price { get { return price; } set { price = value; } }

        public OrderDetails()
        {
            this.Name = string.Empty;
            this.Number = 0;
            this.Price = 0;
        }

        public OrderDetails(string name, int number, double price)
        {
            this.Name = name;
            this.Number = number;
            this.Price = price;
        }

        public double getAllPrice()
        {
            return this.price * this.number;
        }

    }

    public class Order : IComparable
    {
        public int Id { get; set; }
        public string Customer { get; set; }
        public string Date { get; set; }
        public double Money { get; set; }

        public List<OrderDetails> orderDetails = new List<OrderDetails>();


        public Order()
        {
            this.Id = 0;
            this.Customer = string.Empty;
            this.Date = string.Empty;
            this.Money = 0;
        }

        public Order(int id, string customer, string date)
        {
            this.Id = id;
            this.Customer = customer;
            this.Date = date;
            this.Money = 0;
        }

        public void setMoney()
        {
            double money = 0;
            foreach (OrderDetails details in orderDetails)
            {
                money += details.getAllPrice();
            }
            this.Money = money;
        }

        public void addOrderDetails(string name, int number, double price)
        {
            OrderDetails details = new OrderDetails(name, number, price);
            this.orderDetails.Add(details);
        }

        public void removeOrderDetails()
        {
            Console.WriteLine("Please intput the id of the orderdetails to remove:");
            int id = Convert.ToInt32(Console.ReadLine());
            this.orderDetails.RemoveAt(id);
            Console.WriteLine("Remove successfully");
        }

        public void showOrderDetails()
        {
            foreach (OrderDetails details in this.orderDetails)
            {
                Console.WriteLine("Id Name Number Price");
                Console.WriteLine("{0} {1} {2} {3}",
                    this.orderDetails.IndexOf(details), details.Name, details.Number, details.Price);
            }
        }

        #region IComparable Members
        public int CompareTo(object obj)
        {
            if (obj != null)
            {
                Order order = obj as Order;
                return this.Id.CompareTo(order.Id);
            }
            else
                return -1;
        }

        public override bool Equals(object obj)
        {
            Order order = (obj as Order);
            return this.Id.Equals(order?.Id);
        }

        public override int GetHashCode()
        {
            return Convert.ToInt32(this.Id);
        }

        public override string ToString()
        {
            string str = this.Id.ToString() + " " +
                         this.Customer.ToString() + " " +
                         this.Date.ToString() + " " +
                         this.Money.ToString();
            return str;
        }
    }



    public class OrderService : IOrderService
    {
        public List<Order> orders = new List<Order>();

        public OrderService() { }

        public void export()
        {
            XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<Order>));
            using (FileStream fileStream = new FileStream("OrderList.xml", FileMode.Create))
            {
                xmlSerializer.Serialize(fileStream, this.orders);
            }
            Console.WriteLine("Xml Serialize successfully");
        }

        public void import()
        {
            XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<Order>));
            using (FileStream fileStream = new FileStream("OrderList.xml", FileMode.Open))
            {
                orders = (List<Order>)xmlSerializer.Deserialize(fileStream);
            }
        }

        public void addOrder(Order order)
        {
            if (orders.Contains(order))
            {
                throw new OrderExistsException("This order to add is existed");
            }
            orders.Add(order);

        }

        public void removeOrder(int id)
        {
            bool flag = false;
            foreach (Order order in orders)
            {
                if (order.Id == id)
                {
                    flag = true;
                }
            }
            if (flag == true)
            {
                orders.Remove(orders[id]);
            }
            else
            {
                throw new OrderInvalidException("This order to remove is not exist");
            }
        }

        public List<Order> searchOrderInId(int id)
        {
            var queryInId = from order in orders
                            where order.Id == id
                            orderby order.Money
                            select order;
            return queryInId.ToList();
        }
        public List<Order> searchOrderInCustomer(string customer)
        {
            var queryInCustomer = from order in this.orders
                                  where order.Customer == customer
                                  orderby order.Money
                                  select order;
            return queryInCustomer.ToList();

        }

        public List<Order> searchOrderInMoney(string op, int num)
        {
            IOrderedEnumerable<Order> queryInMoney;
            switch (op)
            {
                case "max":
                    queryInMoney = from order in this.orders
                                   where order.Money <= num
                                   orderby order.Money
                                   select order;
                    break;
                case "min":
                    queryInMoney = from order in this.orders
                                   where order.Money >= num
                                   orderby order.Money
                                   select order;
                    break;
                default:
                    queryInMoney = null;
                    break;

            }
            return queryInMoney.ToList();
        }

        public List<Order> searchOrder(string op, object content)
        {
            List<Order> orders = new List<Order>();
            switch (op)
            {
                case "id":
                    int id = Convert.ToInt32(content);
                    orders = searchOrderInId(id);
                    break;
                case "customer":
                    string customer = content.ToString();
                    orders = searchOrderInCustomer(customer);
                    break;
                case "max":
                    int max = Convert.ToInt32(content);
                    orders = searchOrderInMoney(op, max);
                    break;
                case "min":
                    int min = Convert.ToInt32(content);
                    orders = searchOrderInMoney(op, min);
                    break;
            }
            return orders;
        }

        public void sortOrder(string op = "id")
        {
            switch (op)
            {
                case "id":
                    orders.Sort((o1, o2) => o1.Id.CompareTo(o2.Id));
                    break;
                case "customer":
                    orders.Sort((o1, o2) => o1.Customer.CompareTo(o2.Customer));
                    break;
                case "money":
                    orders.Sort((o1, o2) => o1.Money.CompareTo(o2.Money));
                    break;
                default:
                    Console.WriteLine("Invalid sort operation");
                    break;
            }
        }

        public void showOrders()
        {
            foreach (var order in orders)
            {
                Console.WriteLine("Id Customer Date Money");
                Console.WriteLine("{0} {1} {2} {3}",
                    order.Id, order.Customer, order.Date, order.Money);
                order.showOrderDetails();
            }
        }


        public class OrderExistsException : ApplicationException
        {
            public OrderExistsException(string message) : base(message)
            {
            }
        }

        public class OrderInvalidException : ApplicationException
        {
            public OrderInvalidException(string message) : base(message)
            {
            }
        }

    }


}
#endregion